package com.laiketui.online.message.api;

import com.alibaba.fastjson.JSON;
import com.laiketui.common.api.PubliceService;
import com.laiketui.common.mapper.MchModelMapper;
import com.laiketui.common.mapper.OnlineMessageModelMapper;
import com.laiketui.common.mapper.UserBaseMapper;
import com.laiketui.common.utils.tool.DateUtil;
import com.laiketui.common.utils.tool.cache.RedisDataTool;
import com.laiketui.common.utils.tool.str.StringUtils;
import com.laiketui.core.cache.RedisUtil;
import com.laiketui.core.common.SplitUtils;
import com.laiketui.core.exception.LaiKeAPIException;
import com.laiketui.core.lktconst.GloabConst;
import com.laiketui.core.utils.tool.DataUtils;
import com.laiketui.domain.lktconst.ErrorCode;
import com.laiketui.domain.mch.MchModel;
import com.laiketui.domain.onlinemessage.OnlineMessageModel;
import com.laiketui.domain.user.User;
import com.laiketui.domain.vo.MainVo;
import com.laiketui.domain.vo.onlinemessage.AddOnlineMessageVo;
import com.laiketui.online.message.common.consts.OnlineMessageConst;
import com.laiketui.online.message.websocket.WebSocketServer;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class OnlineMessageServiceImpl implements OnlineMessageService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private OnlineMessageModelMapper onlineMessageModelMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserBaseMapper userBaseMapper;

    @Autowired
    private PubliceService publiceService;

    @Autowired
    private WebSocketServer webSocketServer;

    @Autowired
    public ThreadPoolTaskExecutor asyncUploadExcelExecutor;

    @Autowired
    private MchModelMapper mchModelMapper;

    @Override
    public Map<String, Object> getMessageList(MainVo vo, String userId, String mchId, Integer type) throws LaiKeAPIException {
        Map<String, Object> resultMap = new HashMap<>(16);
        try {
            //多端登录校验
            RedisDataTool.isLogin(vo.getAccessId(), redisUtil);
            if (userId == null || mchId == null) {
                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_CSCW, "参数错误");
            }

            List<Map<String, Object>> messageList = onlineMessageModelMapper.getMessageListByParams(vo.getStoreId(), userId, mchId, null);
            for (Map<String, Object> map : messageList) {
                // 是否为店铺 0 否 1 是
                Integer is_mch_send = DataUtils.getIntegerVal(map, "is_mch_send");
                if (1 == is_mch_send) {
                    // 设置图片路径
                    map.put("img", publiceService.getImgPath(MapUtils.getString(map, "img"), vo.getStoreId()));
                }
            }
            // 设置消息已读
            if (OnlineMessageModel.SEND_TYPE_USER.equals(type)) {
                //返回用户头像
                User user = userBaseMapper.selectByUserIdOne(vo.getStoreId(), userId);
                String headimgurl = user.getHeadimgurl();
                if (headimgurl == null){
                    headimgurl = "";
                }
                resultMap.put("userImg", headimgurl);
                onlineMessageModelMapper.updateIsRead(vo.getStoreId(), mchId, userId);
            } else {
                onlineMessageModelMapper.updateIsRead(vo.getStoreId(), userId, mchId);
            }
            resultMap.put("list", messageList);
        } catch (LaiKeAPIException l) {
            throw l;
        } catch (Exception e) {
            logger.error("查询在线消息 异常", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_ZFSB, "查询在线消息异常", "getMessageList");
        }

        return resultMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMessage(AddOnlineMessageVo addOnlineMessageVo) throws LaiKeAPIException {
        try {
            //多端登录校验
            RedisDataTool.isLogin(addOnlineMessageVo.getAccessId(), redisUtil);
            if (addOnlineMessageVo.getIs_mch_send() == null) {
                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_CSCW, "参数错误");
            }

            if (!addOnlineMessageVo.getIs_mch_send().equals(OnlineMessageModel.SEND_TYPE_USER) && !addOnlineMessageVo.getIs_mch_send().equals(OnlineMessageModel.SEND_TYPE_MCH)) {
                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_CSCW, "参数错误");
            }
            List<OnlineMessageModel> addList = new ArrayList<>();
            if (addOnlineMessageVo.getImg_list() == null || addOnlineMessageVo.getImg_list().size() == 0) {
                OnlineMessageModel onlineMessageModel = new OnlineMessageModel();
                onlineMessageModel.setStore_id(addOnlineMessageVo.getStoreId());
                onlineMessageModel.setAdd_date(new Date());
                onlineMessageModel.setSend_id(addOnlineMessageVo.getSend_id());
                onlineMessageModel.setReceive_id(addOnlineMessageVo.getReceive_id());
                onlineMessageModel.setContent(addOnlineMessageVo.getContent());
                onlineMessageModel.setIs_mch_send(addOnlineMessageVo.getIs_mch_send());
                // 设置为未读
                onlineMessageModel.setIs_read(0);
                addList.add(onlineMessageModel);
            } else {
                //批量发送图片
                for (String img : addOnlineMessageVo.getImg_list()) {
                    OnlineMessageModel onlineMessageModel = new OnlineMessageModel();
                    onlineMessageModel.setStore_id(addOnlineMessageVo.getStoreId());
                    onlineMessageModel.setAdd_date(new Date());
                    onlineMessageModel.setSend_id(addOnlineMessageVo.getSend_id());
                    onlineMessageModel.setReceive_id(addOnlineMessageVo.getReceive_id());
                    onlineMessageModel.setContent(img);
                    onlineMessageModel.setIs_mch_send(addOnlineMessageVo.getIs_mch_send());
                    // 设置为未读
                    onlineMessageModel.setIs_read(0);
                    addList.add(onlineMessageModel);
                }
            }

            //添加消息
            onlineMessageModelMapper.insertList(addList);

            // websocket map 对应key
            String key;
            String tokey;
            String fromKey;
            String userId;
            String mchId;
            //用户列表
            String userKey;
            if (addOnlineMessageVo.getIs_mch_send().equals(OnlineMessageModel.SEND_TYPE_USER)) {
                userId = addOnlineMessageVo.getSend_id();
                mchId = addOnlineMessageVo.getReceive_id();
//                key = addOnlineMessageVo.getReceive_id() + SplitUtils.DH + addOnlineMessageVo.getReceive_id();
//                tokey = key;
                fromKey = mchId + SplitUtils.DH + mchId;
                userKey = userId + SplitUtils.DH + userId;
            } else {
                userId = addOnlineMessageVo.getReceive_id();
                mchId = addOnlineMessageVo.getSend_id();
//                key = addOnlineMessageVo.getReceive_id() + SplitUtils.DH + addOnlineMessageVo.getSend_id();
//                tokey = key ;
                fromKey = mchId + SplitUtils.DH + mchId;
                userKey = userId + SplitUtils.DH + userId;
            }

            //消息id集合
            List<Integer> idList = addList.stream().map(OnlineMessageModel::getId).collect(Collectors.toList());
            //查询消息
            List<Map<String, Object>> messageList = onlineMessageModelMapper.getMessageListByParams(addOnlineMessageVo.getStoreId(), userId, mchId, idList);
            //推送发送的最后一条数据
            String finallyMessage = "";
            for (Map<String, Object> map : messageList) {
                finallyMessage = MapUtils.getString(map, "content");
                // 是否为店铺 0 否 1 是
                Integer is_mch_send = DataUtils.getIntegerVal(map, "is_mch_send");
                if (OnlineMessageModel.SEND_TYPE_MCH.equals(is_mch_send)) {
                    map.put("img", publiceService.getImgPath(MapUtils.getString(map, "img"), addOnlineMessageVo.getStoreId()));
                }
                //异步编排多端消息推送
                CompletableFuture<Void> AppLetFuture = CompletableFuture.runAsync(() -> {
                    // 推送消息->小程序
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.APPLET + fromKey, JSON.toJSONString(map));
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.APPLET + userKey, JSON.toJSONString(map));
                }, asyncUploadExcelExecutor).exceptionally(ex -> {
                    if (ex != null){
                        logger.error("推送消息->小程序失败fromKey{},userKey{}", fromKey, userKey);
                        logger.error(ex.getMessage());
                    }
                            return null;
                    });

                CompletableFuture<Void> PcStoreFuture = CompletableFuture.runAsync(() -> {
                    // 推送消息->pc端商城
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.PcStore + fromKey, JSON.toJSONString(map));
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.PcStore + userKey, JSON.toJSONString(map));
                }, asyncUploadExcelExecutor).exceptionally(ex -> {
                    if (ex != null){
                        logger.error("推送消息->pc端商城fromKey{},userKey{}", fromKey, userKey);
                        logger.error(ex.getMessage());
                    }
                    return null;
                });

                CompletableFuture<Void> H5Future = CompletableFuture.runAsync(() -> {
                    // 推送消息->H5    H5_1,1
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.H5 + fromKey, JSON.toJSONString(map));
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.H5 + userKey, JSON.toJSONString(map));
                }, asyncUploadExcelExecutor).exceptionally(ex -> {
                    if (ex != null){
                        logger.error("推送消息->H5fromKey{},userKey{}", fromKey, userKey);
                        logger.error(ex.getMessage());
                    }
                    return null;
                });

                CompletableFuture<Void> PcMchFuture = CompletableFuture.runAsync(() -> {
                    // 推送消息->pc店铺
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.PcMch + fromKey, JSON.toJSONString(map));
                    webSocketServer.sendMessage(OnlineMessageConst.StoreType.PcMch + userKey, JSON.toJSONString(map));
                }, asyncUploadExcelExecutor).exceptionally(ex -> {
                    if (ex != null){
                        logger.error("推送消息->pc店铺fromKey{},userKey{}", fromKey, userKey);
                        logger.error(ex.getMessage());
                    }
                    return null;
                });
                //等待全部发送结束
                CompletableFuture.allOf(AppLetFuture, PcStoreFuture, H5Future, PcMchFuture).join();
            }

            // websocket 推送店铺的用户会话列表
            if (OnlineMessageModel.SEND_TYPE_USER.equals(addOnlineMessageVo.getIs_mch_send())) {
                List<Map<String, Object>> mchUserList = onlineMessageModelMapper.mchUserList(addOnlineMessageVo.getStoreId(), mchId, userId, null);
                if (mchUserList != null && mchUserList.size() > 0) {
                    Map<String, Object> map = mchUserList.get(0);
                    // 设置用户列表在线状态
                    Object user_id = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG + map.get("user_id"));
                    if (user_id != null) {
                        map.put("is_online", 1);
                    }
                    //如果用户头像为空默认设置“”
                    String headimgurl = MapUtils.getString(map, "headimgurl");
                    if (null == headimgurl) {
                        map.put("headimgurl", "");
                    }
                    //发送的最后一条信息
                    map.put("content", finallyMessage);
                    //websocket店铺推送当前用户状态信息
                    Enumeration<String> keys = WebSocketServer.webSocketMap.keys();
                    while (keys.hasMoreElements()) {
                        String mapKey = keys.nextElement();
                        String mch_id = mapKey.substring(mapKey.indexOf(",") + 1);
                        if (mchId.equals(mch_id)) {
                            webSocketServer.sendMessage(mapKey, JSON.toJSONString(map));
                            break;
                        }
                    }
                }
            }else {
                //websocket 推送用户的店铺会话列表
                List<Map<String, Object>> userMchList = onlineMessageModelMapper.getUserMchList(addOnlineMessageVo.getStoreId(), mchId, userId);
                if (userMchList != null && userMchList.size() > 0) {
                    Map<String, Object> map = userMchList.get(0);
                    // 设置店铺列表在线状态
                    //h5店铺
                    Object H5Mch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG + map.get("user_id"));
                    //pc店铺
                    Object PcMch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_STORE_MCH_FLAG + map.get("user_id"));
                    if (H5Mch != null || PcMch != null) {
                        map.put("is_online", 1);
                    }
                    //如果店铺头像为空默认设置“”
                    String headimgurl = MapUtils.getString(map, "headimgurl");
                    headimgurl =  publiceService.getImgPath(headimgurl, addOnlineMessageVo.getStoreId());
                    if (null == headimgurl) {
                        map.put("headimgurl", "");
                    }else {
                        map.put("headimgurl", headimgurl);
                    }
                    map.put("content", finallyMessage);
                    //websocket用户推送当前店铺状态信息
                    Enumeration<String> keys = WebSocketServer.webSocketMap.keys();
                    while (keys.hasMoreElements()) {
                        String mapKey = keys.nextElement();
                        String user_id = mapKey.substring(mapKey.indexOf(",") + 1);
                        if (userId.equals(user_id)) {
                            webSocketServer.sendMessage(mapKey, JSON.toJSONString(map));
                            break;
                        }
                    }
                }
            }
        } catch (LaiKeAPIException l) {
            throw l;
        } catch (Exception e) {
            logger.error("查询在线消息 异常", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_ZFSB, "添加在线消息", "addMessage");
        }
    }

    @Override
    public Map<String, Object> mchUserList(MainVo vo, String mchId, String userName) throws LaiKeAPIException {
        Map<String, Object> resultMap = new HashMap<>(16);
        try {
            //多端登录校验
            RedisDataTool.isLogin(vo.getAccessId(), redisUtil);
            if (mchId == null) {
                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_CSCW, "参数错误");
            }

            List<Map<String, Object>> list = onlineMessageModelMapper.mchUserList(vo.getStoreId(), mchId, null, userName);
            Map<String, Object> mchUserArticleOneMessage;
            // 设置用户列表在线状态
            for (Map<String, Object> map : list) {
                String userId = MapUtils.getString(map, "user_id");
                Object user_id = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG + userId);
                if (user_id != null) {
                    map.put("is_online", 1);
                }
                //如果用户头像为空默认设置“”
                String headimgurl = MapUtils.getString(map, "headimgurl");
                if (null == headimgurl) {
                    map.put("headimgurl", "");
                }
                //获取最近的一条聊天记录
                mchUserArticleOneMessage = onlineMessageModelMapper.getUserMchArticleOneMessage(vo.getStoreId(), mchId, userId);
                if (mchUserArticleOneMessage != null){
                    map.put("content", MapUtils.getString(mchUserArticleOneMessage, "content"));
                    map.put("addTime",getMessageTime(MapUtils.getString(mchUserArticleOneMessage, "add_date")));
                }else {
                    map.put("content", "");
                    //当前时间 HH:mm
                    map.put("addTime",DateUtil.dateFormate(new Date(), GloabConst.TimePattern.HM));
                }
            }

            resultMap.put("list", list);
        } catch (LaiKeAPIException l) {
            throw l;
        } catch (Exception e) {
            logger.error("查询店铺会话的用户列表 异常", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_ZFSB, "查询店铺会话的用户列表", "mchUserList");
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> userMchList(MainVo vo, String userId, String mchId, String mchName) throws LaiKeAPIException {
        Map<String, Object> resultMap = new HashMap<>(16);
        try {
            //多端登录校验
            RedisDataTool.isLogin(vo.getAccessId(), redisUtil);
            if (userId == null) {
                throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_CSCW, "参数错误");
            }
            List<Map<String, Object>> list = onlineMessageModelMapper.userMchList(vo.getStoreId(), null, userId, mchName);
            Map<String, Object> userMchArticleOneMessage;
            Map<String, Object> map = null;
            //商品详情页进入客服,当前商品的店铺在客服列表的第一个
            boolean IsHaveMchId = false;
            // 设置店铺列表在线状态
            for (int i = 0; i < list.size(); i++) {
                map = list.get(i);
                String mch_id = MapUtils.getString(map, "mch_id");
                //h5店铺
                Object H5Mch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG + map.get("user_id"));
                //pc店铺
                Object PcMch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_STORE_MCH_FLAG + map.get("user_id"));
                if (H5Mch != null || PcMch != null) {
                    map.put("is_online", 1);
                }
                //如果店铺头像为空默认设置“”
                String headimgurl = MapUtils.getString(map, "headimgurl");
                headimgurl =  publiceService.getImgPath(headimgurl, vo.getStoreId());
                if (null == headimgurl) {
                    map.put("headimgurl", "");
                }else {
                    map.put("headimgurl", headimgurl);
                }
                //获取最近的一条聊天记录
                userMchArticleOneMessage = onlineMessageModelMapper.getUserMchArticleOneMessage(vo.getStoreId(), mch_id, userId);
                if (userMchArticleOneMessage != null){
                    map.put("content", MapUtils.getString(userMchArticleOneMessage, "content"));
                    map.put("addTime",getMessageTime(MapUtils.getString(userMchArticleOneMessage, "add_date")));
                }else {
                    map.put("content", "");
                    //当前时间 HH:mm
                    map.put("addTime",DateUtil.dateFormate(new Date(), GloabConst.TimePattern.HM));
                }
                //商品详情页进入客服,当前商品的店铺在客服列表的第一个
                if (StringUtils.isNotEmpty(mchId)){
                    if (mchId.equals(mch_id)){
                        IsHaveMchId = true;
                        if (i != 0){
                            Map<String, Object> objectMap = list.get(0);
                            list.set(0, map);
                            list.set(i, objectMap);
                        }
                    }
                }
            }
            //获取当前聊天店铺信息  ->首次建立连接
            if (!IsHaveMchId && StringUtils.isNotEmpty(mchId)){
                Map<String, Object> mchMap = new HashMap<>();
                MchModel mchModel = mchModelMapper.selectByPrimaryKey(mchId);
                if (mchModel == null){
                    throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_CSCW, "参数错误");
                }
                mchMap.put("name", mchModel.getName());
                mchMap.put("mch_id", String.valueOf(mchModel.getId()));
                mchMap.put("user_id", userId);
                mchMap.put("headimgurl", publiceService.getImgPath(mchModel.getHead_img(), vo.getStoreId()));
                //以读
                mchMap.put("no_read_num", 0);
                //是否在线
                mchMap.put("is_online", 0);
                //h5店铺
                Object H5Mch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG + mchModel.getUser_id());
                //pc店铺
                Object PcMch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_STORE_MCH_FLAG + mchModel.getUser_id());
                if (H5Mch != null || PcMch != null) {
                    mchMap.put("is_online", 1);
                }
                mchMap.put("content", "");
                //当前时间 HH:mm
                mchMap.put("addTime",DateUtil.dateFormate(new Date(), GloabConst.TimePattern.HM));
                //首次建立连接，放在第一位
                list.add(0, mchMap);
            }
            //获取当前聊天店铺信息  ->首次建立连接
/*            if (StringUtils.isNotEmpty(mchId)){
                Map<String, Object> mchMap = new HashMap<>();
                MchModel mchModel = mchModelMapper.selectByPrimaryKey(mchId);
                mchMap.put("name", mchModel.getName());
                mchMap.put("mch_id", String.valueOf(mchModel.getId()));
                mchMap.put("user_id", userId);
                mchMap.put("headimgurl", publiceService.getImgPath(mchModel.getHead_img(), vo.getStoreId()));
                //以读
                mchMap.put("no_read_num", 0);
                //是否在线
                mchMap.put("is_online", 0);
                //h5店铺
                Object H5Mch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG + mchModel.getUser_id());
                //pc店铺
                Object PcMch = redisUtil.get(GloabConst.RedisHeaderKey.LOGIN_ACCESS_FLAG_STORE_MCH + mchModel.getUser_id());
                if (H5Mch != null || PcMch != null) {
                    mchMap.put("is_online", 1);
                }
                mchMap.put("content", "");
                //当前时间 HH:mm
                mchMap.put("addTime",DateUtil.dateFormate(new Date(), GloabConst.TimePattern.HM));
                //首次建立连接，放在第一位
                list.add(0, mchMap);
            }*/
            resultMap.put("list", list);
        }catch (LaiKeAPIException l) {
            throw l;
        } catch (Exception e) {
            logger.error("查询用户会话的店铺列表 异常", e);
            throw new LaiKeAPIException(ErrorCode.BizErrorCode.ERROR_CODE_ZFSB, "查询用户会话的店铺列表", "userMchList");
        }
        return resultMap;
    }

    /**
     * 消息时间特殊处理
     * @param time
     * @return
     */
    private static String getMessageTime(String time){
        //判断时间是否是当天
        // 当前时间
        Date now = new Date();
        SimpleDateFormat sf = new SimpleDateFormat(GloabConst.TimePattern.YMD);
        //获取今天的日期
        String nowDay = sf.format(now);
        //对比的时间
        if (sf.format(DateUtil.dateFormateToDate(time, GloabConst.TimePattern.YMD)).equals(nowDay)){
            //当天 -> 返回 HH:mm
            return DateUtil.dateFormate(time, GloabConst.TimePattern.HM);
        }else {
            //非当天-> 返回 MM/dd
            return DateUtil.dateFormate(time, GloabConst.TimePattern.MD1);

        }
    }
}
